package fr.univ.colloque.dao;

import fr.univ.colloque.data.Candidat;
import fr.univ.colloque.data.Expose;
import fr.univ.colloque.data.Institution;
import fr.univ.colloque.data.Membre;
import fr.univ.colloque.data.MotCle;
import fr.univ.colloque.data.Notation;
import fr.univ.colloque.data.Personne;
import fr.univ.colloque.data.President;
import fr.univ.colloque.data.Type;
import fr.univ.colloque.util.PoolConnexion;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class PersonneDao
{

    /**
     * Vérifie que le couple (login, password) passé en paramètre est conforme
     *
     * @param login login de la personne voulant se connecter
     * @param password password de la personne voulant se connecter
     * @return la personne correspondant au couple login/password ou null si non
     * conforme
     */
    public Personne seConnecter(String login, String password)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select * from PERSONNE where login=?";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Personne personne = null;
        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setString(1, login);
            rs = pStat.executeQuery();

            if (rs.next())
            {
                String passwordBdd = rs.getString("password");

                if (password.equals(passwordBdd))
                {
                    // Ok le couple login / password est le bon 
                    personne = new Candidat();

                    int idType = rs.getInt("id_type");

                    if (Type.get(idType).equals(Type.CANDIDAT))
                    {
                        personne = new Candidat();
                    }
                    else if (Type.get(idType).equals(Type.MEMBRE))
                    {
                        personne = new Membre();
                    }
                    else if (Type.get(idType).equals(Type.PRESIDENT))
                    {
                        personne = new President();
                    }

                    personne.setId(rs.getInt("id_pers"));
                    personne.setLogin(login);
                    personne.setEmail(rs.getString("email"));
                    personne.setNom(rs.getString("nom"));
                    personne.setPrenom(rs.getString("prenom"));

                    int idInstit = rs.getInt("id_instit");

                    // appel du dao qui va récupérer l'objet Type à partir de l'idType
                    //    Type type = Type.get(idType);
                    //    personne.setType(type);

                    // appel du dao qui va récupérer l'objet Institution à partir de l'idInstit
                    InstitutionDao iDao = new InstitutionDao();
                    Institution instit = iDao.get(idInstit);
                    personne.setInstitution(instit);
                }
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return personne;
    }

    public Membre getEvalById(int id)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select * from PERSONNE where id_pers=?";
        String requeteNote = "select * from GERER where id_pers=?";

        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Membre membre = null;

        try
        {

            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, id);
            rs = pStat.executeQuery();

            if (rs.next())
            {
                // Ok le couple login / password est le bon 
                membre = new Membre();
                membre.setId(rs.getInt("id_pers"));
                membre.setLogin(rs.getString("login"));
                membre.setEmail(rs.getString("email"));
                membre.setNom(rs.getString("nom"));
                membre.setPrenom(rs.getString("prenom"));

                int idInstit = rs.getInt("id_instit");

                // appel du dao qui va récupérer l'objet Institution à partir de l'idInstit
                InstitutionDao iDao = new InstitutionDao();
                Institution instit = iDao.get(idInstit);
                membre.setInstitution(instit);
            }


            pStat = con.prepareStatement(requeteNote);
            pStat.setInt(1, id);
            rs = pStat.executeQuery();
            ExposeDao eDao = new ExposeDao();
            Map<Expose, Notation> mapNote = new HashMap<Expose, Notation>();
            while (rs.next())
            {
                int id_exp = rs.getInt("id_exp");
                String nPertStr = rs.getString("pertinence");
                String nImpStr = rs.getString("importance");
                String nLisStr = rs.getString("lisibilite");
                String nDecStr = rs.getString("decisionFinale");

                Expose e = eDao.get(id_exp, false, false);

                Notation n = null;

                if (nPertStr != null)
                {
                    n = new Notation(Integer.parseInt(nPertStr), Integer.parseInt(nImpStr), Integer.parseInt(nLisStr), Integer.parseInt(nDecStr));
                }

                mapNote.put(e, n);
            }

            membre.setExpoAffecter(mapNote);

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return membre;
    }

    /**
     * Récupère la personne correspondant à l'identifiant
     *
     * @param id identifiant de la personne
     * @return
     */
    public Personne get(int id)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select * from PERSONNE where id_pers=?";

        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Personne personne = null;
        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, id);
            rs = pStat.executeQuery();

            if (rs.next())
            {
                // Ok le couple login / password est le bon 
                personne = new Personne();
                personne.setId(rs.getInt("id_pers"));
                personne.setLogin(rs.getString("login"));
                personne.setEmail(rs.getString("email"));
                personne.setNom(rs.getString("nom"));
                personne.setPrenom(rs.getString("prenom"));

                int idType = rs.getInt("id_type");
                int idInstit = rs.getInt("id_instit");

                // appel du dao qui va récupérer l'objet Type à partir de l'idType
                Type type = Type.get(idType);
                personne.setType(type);

                // appel du dao qui va récupérer l'objet Institution à partir de l'idInstit
                InstitutionDao iDao = new InstitutionDao();
                Institution instit = iDao.get(idInstit);
                personne.setInstitution(instit);
            }
        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
        return personne;
    }

    /**
     * Enregistre la personne dans la bdd
     *
     * @param personne personne à enregistrer
     * @return l'identifiant de la personne enregistrée
     */
    public Integer save(Personne personne)
    {
        String requete = "insert into PERSONNE (nom, prenom, email,login,password,id_instit,id_type) values (?,?,?,?,?,?,?)";

        PoolConnexion pool = PoolConnexion.getInstance();

        PreparedStatement pStat = null;
        ResultSet rs = null;

        Connection con = null;

        Integer id = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete, Statement.RETURN_GENERATED_KEYS);
            pStat.setString(1, personne.getNom());
            pStat.setString(2, personne.getPrenom());
            pStat.setString(3, personne.getEmail());
            pStat.setString(4, personne.getLogin());
            pStat.setString(5, personne.getPassword());
            pStat.setInt(6, personne.getInstitution().getId());
            pStat.setInt(7, personne.getType().getId());

            pStat.executeUpdate();

            rs = pStat.getGeneratedKeys();

            if (rs.next())
            {
                id = rs.getInt(1);
            }
        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return id;
    }

    /**
     * Retourne un évaluateur qui n'a pas déjà été choisi, qui a un mot clé qui
     * correspond et qui n'est pas de la même institution
     *
     * @param lMc liste des mots clés recherchés pour l'évaluateur
     * @param listPersExist liste des évaluateurs déjà choisis
     * @param idInstit identifiant de l'institution interdite
     *
     * @return un évaluateur ou null si aucun ne correspond à la recherche
     */
    public Membre trouverEvaluateur(List<MotCle> lMc, List<Integer> listPersExist, int idInstit)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        StringBuilder requete = new StringBuilder("select p.id_pers, p.nom, p.prenom, count(c.id_motCle) 'NbMc' from PERSONNE p, CARACTERISER c where p.id_type=2 and p.id_instit <> ? and p.id_pers=c.id_pers and id_motCle in (");

        for (int i = 0; i < lMc.size(); i++)
        {
            MotCle m = (MotCle) lMc.get(i);
            requete.append(m.getId());
            if (i < (lMc.size() - 1))
            {
                requete.append(",");
            }
        }
        requete.append(") group by c.id_pers order by count(id_motCle) desc");
        String requeteStr = requete.toString();

        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Membre personne = null;
        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requeteStr);
            pStat.setInt(1, idInstit);
            rs = pStat.executeQuery();
            boolean trouve = false;

            for (int i = 0; !trouve && rs.next(); i++)
            {
                personne = new Membre();
                personne.setId(rs.getInt("id_pers"));
                personne.setNom(rs.getString("nom"));
                personne.setPrenom(rs.getString("prenom"));

                if (!listPersExist.contains(personne.getId()))
                {
                    trouve = true;
                }
                else
                {
                    personne = null;
                }
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return personne;
    }

    /**
     * Enrtegistre les évaluateurs affectés aux exposés
     *
     * @param lstExpose liste des exposés avec leurs évaluateurs
     */
    public void enregistrerLesEvaluateurs(List<Expose> lstExpose)
    {
        for (Expose exp : lstExpose)
        {
            if (exp.getEvaluateur1() != null)
            {
                ajouterEvaluateur(exp.getEvaluateur1().getId(), exp.getId());
            }

            if (exp.getEvaluateur2() != null)
            {
                ajouterEvaluateur(exp.getEvaluateur2().getId(), exp.getId());
            }

        }
    }

    /**
     * Ajoute un évaluateur à un exposé
     *
     * @param idEval identifiant de l'évaluateur
     * @param idExpo identifiant de l'exposé
     */
    public void ajouterEvaluateur(int idEval, int idExpo)
    {
        String requete = "insert into GERER (id_pers,id_exp) values (?,?)";

        PoolConnexion pool = PoolConnexion.getInstance();

        PreparedStatement pStat = null;
        ResultSet rs = null;

        Connection con = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, idEval);
            pStat.setInt(2, idExpo);

            pStat.executeUpdate();
        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
    }

    /**
     * Remplace un évaluateur par un autre pour un exposé
     *
     * @param idNewEval identifiant du nouvel évaluateur
     * @param idOldEval identifiant de l'ancien évaluateur
     * @param idExpo identifiant de l'exposé
     */
    public void majEvaluateur(int idNewEval, int idOldEval, int idExpo)
    {
        String requete = "update GERER set id_pers=? where id_pers=? and id_exp=?";

        PoolConnexion pool = PoolConnexion.getInstance();

        PreparedStatement pStat = null;
        ResultSet rs = null;

        Connection con = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, idNewEval);
            pStat.setInt(2, idOldEval);
            pStat.setInt(3, idExpo);

            pStat.executeUpdate();
        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
    }

    /**
     * Retourne la liste des évaluateurs qui ne sont pas affectés à ce colloque
     *
     * @param idColloque identifiant du colloque
     * @return
     */
    public List<Personne> getEvaluateurLibre(int idColloque)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select p.* from PERSONNE p where id_type = 2 and p.id_pers not in(select g.id_pers from GERER g where g.id_exp in ( select e.id_exp from EXPOSE e where e.id_colloc = ?))";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        MotCleDao mDao = new MotCleDao();

        List<Personne> lPers = new ArrayList<Personne>();
        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, idColloque);
            rs = pStat.executeQuery();

            while (rs.next())
            {
                Personne personne = new Personne();
                personne.setId(rs.getInt("id_pers"));
                personne.setLogin(rs.getString("login"));
                personne.setEmail(rs.getString("email"));
                personne.setNom(rs.getString("nom"));
                personne.setPrenom(rs.getString("prenom"));

                int idType = rs.getInt("id_type");
                int idInstit = rs.getInt("id_instit");

                // appel du dao qui va récupérer l'objet Type à partir de l'idType
                Type type = Type.get(idType);
                personne.setType(type);

                // appel du dao qui va récupérer l'objet Institution à partir de l'idInstit
                InstitutionDao iDao = new InstitutionDao();
                Institution instit = iDao.get(idInstit);
                personne.setInstitution(instit);


                List<MotCle> lMc = mDao.getPersonneMc(personne.getId());
                personne.setListeMotCle(lMc);

                lPers.add(personne);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
        return lPers;
    }

    /**
     * Test si le mail passé en paramètre correspond à une personne connue dans
     * la bdd
     *
     * @param email email à chercher dnas la base de données
     *
     * @return true si il est trouvé dans la bdd, sinon false
     */
    public boolean isEmailExist(String email)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        boolean existe = false;

        String requete = "select * from PERSONNE where email=?";

        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Personne personne = null;
        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setString(1, email);
            rs = pStat.executeQuery();

            if (rs.next())
            {

                existe = true;
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
        return existe;
    }
}